#ifndef SYMBOL_H
#define SYMBOL_H

#include <stdio.h>
#include <string.h>
#include "CoffStructs.h"

class Coff;

class Symbol {
	SymbolEntry* entry;	// Entry readed
	int number;			// Table index
	char *name;			// Dinamic allocated name
public:
	Symbol(int num, Coff *c); // TODO: read entry 
	~Symbol();				  // TODO
	int numberOfAuxs()	{ return entry->nAuxSymbols; }
	char *getName()		{ return name; }
	int getNumber()		{ return number; }
	int getSectionId()  { return entry->section; }
	int getStorage()    { return entry->storage; }
	int getType()       { return entry->type;    }    
	// ADD more methods 
};

class SymIterator {
public:
	virtual ~SymIterator() {}
	virtual Symbol * next() = 0;
};

class GlobalSymIterator : public SymIterator{
private:
	int c;   //Symbol Count 
	Symbol** s;
	int cursor;
public:
	GlobalSymIterator(Symbol** symbols, int count){
		c      = count;
		s      = symbols;
		cursor = 0;
	}

	~GlobalSymIterator(){}

	Symbol* next(){
		Symbol* tmp;
		while( cursor < c ){
			tmp = s[cursor];
			cursor += tmp->numberOfAuxs() + 1;
			return tmp;
		}

		return NULL;
	}
};

class DefinedSymIterator : public SymIterator{
private:
	int sId;      //sectionId
	char* sName;  //Section Name
	int c;        //Symbol Count 
	Symbol** s;
	int cursor;
public:
	DefinedSymIterator(int sectionId, char* sectionName, Symbol** symbols, int count){
		sId    = sectionId;
		sName  = sectionName;
		c      = count;
		s      = symbols;
		cursor = 0;
	}

	~DefinedSymIterator(){}

	Symbol* next(){
		while( cursor < c ){
			if( s[cursor]->getSectionId() == sId ){
				if( strcmp(s[cursor]->getName(), sName) != 0 )
					return s[cursor++];
			}
			cursor += 1;
		}

		return NULL;
	}
};

class ReferencedSymIterator : public SymIterator{
private:
	Symbol** s;
	RelocationEntry **r;
	int count;
	int iptr; // Iterator Pointer
public:
	ReferencedSymIterator(FILE* fp, int numberOfRelocations, int pointerToRelocations, Symbol** symbols){
		RelocationEntry* buffer;
		s     = symbols;
		count = numberOfRelocations;
		r     = (RelocationEntry**)malloc(sizeof(RelocationEntry) * numberOfRelocations);
		iptr  = 0;

		int cpos = ftell(fp); // backup the current position
		fseek(fp, pointerToRelocations, SEEK_SET); 
		for(int i = 0; i < numberOfRelocations; i++){
			buffer = (RelocationEntry*)malloc(sizeof(RelocationEntry));
			fread(buffer, sizeof(RelocationEntry), 1, fp);
			r[i] = buffer;
		}
		fseek(fp, cpos, SEEK_SET); // restore the old position, just in case ... 
	}

	~ReferencedSymIterator(){
		for( int i = 0; i < count;i++ ){
			free( r[i] );
		}

		free(r);
	}

	Symbol* next(){
		if( iptr < count ){
			return s[ r[iptr++]->symbolIndex ];
		}
		return NULL;
	}
};
#endif
